//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//


#pragma once

//
// Defines
//

#define MAX_DTR_ATTEMPTS            1
#define MAX_ATO_ATTEMPTS            3

#define TIMEOUT_CMD_ONLINE          10000
#define TIMEOUT_CMD_NOOP            10000
#define MAX_RING_INTERVAL_TIME      8000 //7s: 4s off, 1s on

#define RIL_FFUART_BAUDRATE   CBR_57600 //CBR_115200

#define STAT_BUCKETS                10
#define STAT_BUCKET_WEIGHTS         (STAT_BUCKETS * (STAT_BUCKETS + 1) / 2)

#define CMD_MODE_MASK               (EV_DSR | EV_RLSD)
#define CMD_MODE_STATUS             (MS_DSR_ON | MS_RLSD_ON)


#define MIN_TIME_BEFORE_ABORT       200

#define ABORT_COMMAND               "\r\r\033"
#define ABORT_COMMAND_SIZE          strlen(ABORT_COMMAND)


struct WCETIMEOUT_THREAD_DATA {
    DWORD dwTimeout;
    HANDLE hCancelEvent;
    HANDLE hPort;
};

#define TIMEOUT_DTRDROP             5000

//
// Forward declarations
//
class CComInstanceHandle;

//
// Virtual serial device handle
//
class CComHandle
{
public:
               CComHandle(COM_PORT_TYPE PortType);
               ~CComHandle();

  COM_PORT_TYPE GetPortType() const { return m_PortType; };
  BOOL         Init();
  BOOL         OpenDownstreamPort();
  BOOL         CloseDownstreamPort();
  void         SetExternalCancelEvent(HANDLE hEvent) { SYNCBLOCK(m_csPortHandle); m_hExternalCancelEvent = hEvent; };
  BOOL         IOControl(const DWORD dwCode, const BYTE* const pBufIn, const DWORD dwLenIn, BYTE* const pBufOut,
                         const DWORD dwLenOut, DWORD& rdwActualOut, BOOL fLockSignals) const;
  BOOL         WriteCharsToComPort(CRilHandle* const pRilDevice, LPCSTR szChars, UINT cbToWrite);
  BOOL         WriteCmdsToComPort (CRilHandle* const pRilDevice, LPCSTR szChars, UINT cbToWrite);
  void         LockRILCmd() { EnterCriticalSection(&m_csAbortCommand); };
  void         UnlockRILCmd() { LeaveCriticalSection(&m_csAbortCommand); };
  BOOL         SendRILCmdHandleRsp(CRilHandle* const pRilDevice, CCommand*& rpCmd, BOOL& rfHungUp, BOOL& rfTimedOut);
  BOOL         EnterDataMode(const LPCSTR szData, const UINT cbData);
  BOOL         ExitDataMode();
  BOOL         TerminateDataMode();
  BOOL         FDataMode()
                 { SYNCBLOCK(m_csDataMode); return m_fDataMode; };
    
  BOOL         WaitForCommandMode(DWORD dwTimeOut = INFINITE) const;
  BOOL         AbortCommand();
  UINT         ReadFromBackupBuffer(void* const pDestination, const DWORD cbToRead);
  BOOL         InitComPortForRIL(DCB* const pdcbOld, COMMTIMEOUTS* const pctOld) const;
  BOOL         SetOwner(const CComInstanceHandle* const pHandle);
  BOOL         ClearOwner(const CComInstanceHandle* const pOwner);
  BOOL         FHandleIsOwner(const CComInstanceHandle* const pHandle)
                 { SYNCBLOCK(m_csOwner); return (pHandle == m_pOwner); };
  void         UpdateComStatData(const BOOL fRead, const DWORD dwBytes);
  void         CalculateComStats(DWORD& rdwReadBitsPerSec, DWORD& rdwWrittenBitsPerSec);
  DWORD        CalculateCmdModeTime();
  void         SetCancelledDial() { m_fCancelledDial = TRUE; }

  BOOL         VirtRead(void* pBuf, const UINT cb, DWORD& rdwRead) const;
  BOOL         VirtWrite(const void* pBuf, const UINT cb, DWORD& rdwWritten) const;
  BOOL         VirtWaitCommEvent(DWORD* const pdwMask) const;
  BOOL         VirtClearCommBreak() const;
  BOOL         VirtClearCommError(DWORD* const pdwErrors, COMSTAT* const pcs) const;
  BOOL         VirtEscapeCommFunction(const DWORD dwFunc) const;
  BOOL         VirtGetCommMask(DWORD* const pdwMask) const;
  BOOL         VirtSetCommMask(const DWORD dwMask) const;
  BOOL         VirtGetCommModemStatus(DWORD* const pdwStatus) const;
  BOOL         VirtGetCommProperties(COMMPROP* const pcp) const;
  BOOL         VirtGetCommState(DCB* const pdcb) const;
  BOOL         VirtSetCommState(DCB* const pdcb) const;
  BOOL         VirtGetCommTimeouts(COMMTIMEOUTS* const pct) const;
  BOOL         VirtSetCommTimeouts(COMMTIMEOUTS* const pct) const;
  BOOL         VirtPurgeComm(const DWORD dwFlags) const;
  BOOL         VirtSetCommBreak() const;
  BOOL         VirtSetupComm(const DWORD dwInQueue, const DWORD dwOutQueue) const;
  BOOL         VirtTransmitCommChar(const char cChar) const;

  BOOL         InitCommState(DCB* const pdcbOld) const;
  DWORD        GetBaudRate() const         { return m_dwDownstreamBaudRate; };
  DWORD        GetLastCmdTime() const      { return m_dwLastCmdSent; };
  HANDLE       GetPortHandle()             { SYNCBLOCK(m_csPortHandle); return m_hDownstream; };
  BOOL         IsDownstreamPortOpen()      { SYNCBLOCK(m_csPortHandle); return (m_hDownstream != INVALID_HANDLE_VALUE); };
  BOOL         WaitForDownstreamPort();


  BOOL         FEnoughTimeToSendCmd(CCommand* pCmd, DWORD dwTimeLeft) const ;
  BOOL         WaitCommEventWithTimeout(DWORD dwTimeout, DWORD& rdwMask);
  BOOL         GetDTRDropResponse(CRilHandle* const pRilDevice);
  HANDLE       m_hDownstream;

private:
  static DWORD WINAPI CheckCmdModeThread(LPVOID lpParam);

  COM_PORT_TYPE               m_PortType;

  HANDLE                      m_hCComHandleDestroyEvent;
  HANDLE                      m_hCommandModeEvent;
  HANDLE                      m_hComCancelEvent;
  HANDLE                      m_hComInitEvent;
  HANDLE                      m_hExternalCancelEvent;
  BOOL                        m_fCheckCmdMode;
  CBuffer*                    m_pBuffer;
  DWORD                       m_dwDownstreamBaudRate;
  DWORD                       m_dwStatQuantum;
  DWORD                       m_rgdwReadStatBits[STAT_BUCKETS];
  DWORD                       m_rgdwWriteStatBits[STAT_BUCKETS];
  DWORD                       m_dwReadStatTimestamp;
  DWORD                       m_dwWriteStatTimestamp;
  const CComInstanceHandle*   m_pOwner;
  CRITICAL_SECTION            m_csDataMode;
  CRITICAL_SECTION            m_csOwner;
  CRITICAL_SECTION            m_csStats;
  CRITICAL_SECTION            m_csPortHandle;
  CRITICAL_SECTION            m_csAbortCommand;
  DWORD                       m_fInited : 1;
  DWORD                       m_fDataMode : 1;
  DWORD                       m_fCancelledDial : 1;
  DWORD                       m_dwLastCmdSent;
  DWORD                       m_dwLastDataSent;
  BOOL                        m_fCommandOngoing;
  HANDLE                      m_hDataModeInterrupted;
};


//
// Virtual serial instance handle
//
class CComInstanceHandle
{
public:
                      CComInstanceHandle();
                      ~CComInstanceHandle();

  BOOL                Init(CComHandle* const pDevice, const DWORD dwAccess);
  CComHandle*         GetDevice(void) const    { return m_pDevice; };
  BOOL                IsRsaMode(void) const    { return m_fRsaMode; };

private:
  CComHandle*         m_pDevice;
  BOOL                m_fRsaMode;
};


//
// Parameter strcuture passed to HangupThreadProc
//
struct HANGUP_THREAD_DATA {
  HANDLE         hQuitEvent;
  CComHandle*    pComDevice;
  CRilHandle*    pRilDevice;
  COM_PORT_TYPE  PortType;
};


#ifndef UNDER_CE
//
// Operlapped operations
//
enum OVERLAPPED_OPER
{
  OVERLAPPED_WAIT = 1,
  OVERLAPPED_READ,
  OVERLAPPED_WRITE
};

//
// Functions
//
BOOL PerformOverlappedIO(const OVERLAPPED_OPER oper, const HANDLE hCom, void* pbData, UINT cbData, DWORD* pdwData);
#endif // UNDER_CE

